package com.parking.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.parking.common.core.model.PageInfo;
import com.parking.common.core.model.RedisKey;
import com.parking.common.core.model.StateData;
import com.parking.common.core.util.BeanUtilCommon;
import com.parking.common.core.util.DateUtil;
import com.parking.common.core.util.JwtUtil;
import com.parking.common.web.util.RedisUtil;
import com.parking.order.client.dto.*;
import com.parking.order.config.AlipayConfiguration;
import com.parking.order.dao.OrderOvertimeDao;
import com.parking.order.model.OrderInfo;
import com.parking.order.dao.OrderInfoDao;
import com.parking.order.model.OrderOvertime;
import com.parking.order.model.dto.OrderDto;
import com.parking.order.model.dto.OrderInfoDto;
import com.parking.order.model.dto.clientDto.UserOrderDto;
import com.parking.order.model.dto.orderDtos.*;
import com.parking.order.model.param.*;
import com.parking.order.model.exception.OrderException;
import com.parking.order.model.exception.OrderExceptionCode;
import com.parking.order.model.param.*;
import com.parking.order.service.IOrderInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.parking.order.state.CommonOrderStateChange;
import com.parking.order.util.AlipayUtil;
import com.parking.order.util.BasicInfoUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 吴彦祖
 * @since 2023年11月28日
 */
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfo> implements IOrderInfoService {
    /**
     * 工具类 负责调用其他模块接口
     * */
    @Autowired
    private BasicInfoUtil basicInfoUtil;

    /**
     * 订单状态改变工具类
     * */
    @Autowired
    private CommonOrderStateChange commonOrderStateChange;

    /**
     * 支付宝回调接口
     * */
    @Autowired
    private AlipayUtil alipayUtil;

    /**
     * Redis工具类
     * */
    @Autowired
    private RedisUtil redisUtil;

    /**
     * 支付宝配置类
     * */
    @Autowired
    private AlipayConfiguration alipayConfiguration;

    /**
     * 订单信息数据层
     * */
    @Autowired
    private OrderInfoDao orderInfoDao;

    /**
     * 超时订单数据层
     * */
    @Autowired
    private OrderOvertimeDao orderOvertimeDao;

    /**
     * 分布式锁API
     * */
    @Autowired
    private RedissonClient redissonClient;

    /**
     * RabbitMQ消息发送
     * */
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 添加订单
     * 参数: startTime 出租开始时间
     *       endTime  出租结束时间
     *       stallInfoId 车位Id
     *       userCarId   用户车辆Id
     *       Authorization 用户Token
     *
     * 返回: certifiedInfoName    物业名称
     *      certifiedInfoTel     物业电话
     *      certifiedInfoAddress 物业地址
     *      time                 开始时间-结束时间
     *      enduHour             持续小时
     *      orderPrice           订单价格 = enduHour持续小时 * 普通/充电车位价格
     *      orderInfoState       订单状态 = 待支付
     *      orderAddTime         下单时间
     *      orderInfoNum         订单编号
     *      stallType            车位类型 0普通车位 1充电车位
     *      stallInfo            车位号 = stallInfoArea(车位区域) + stallInfoNum(车位编号)
     *      userCarPlate         车牌号
     */
    @Transactional
    @Override
    public OrderDto addOrder(AddOrderParam param) throws Exception {
        System.out.println("====================2.解析userId 状态正常 param包装无误 当前参数如下============================");
        System.out.println("用户Id: "+param.getUserId());
        System.out.println("用户车辆Id: "+param.getUserCarId());
        System.out.println("车位信息Id: "+param.getStallInfoId());
        System.out.println("开始时间: "+param.getStartTime());
        System.out.println("结束时间: "+param.getEndTime());

        System.out.println("=====================3.方法前校验===============================");
        System.out.println("======================3.1.开始结束时间校验: 开始<结束 开始结束时间为最近两天 00/15/30/45 结束-开始=整小时数=============================");
        Integer enduHour = checkStartEnd(param.getStartTime(),param.getEndTime());
        System.out.println("整小时数:"+enduHour);
        System.out.println("=====================3.2用户Id对应用户且状态正常==============================");
        basicInfoUtil.getUser(param.getUserId());
        System.out.println("=====================3.3用户车辆Id对应用户车辆且未被删除==============================");
        UserCarDto userCar = basicInfoUtil.getUserCar(param.getUserCarId());
        System.out.println("用户信息Id:"+userCar.getUserInfoId());
        System.out.println("车牌号:"+userCar.getUserCarPlate());
        System.out.println("车辆联系人:"+userCar.getCarContacts());
        System.out.println("车辆联系人电话:"+userCar.getCarContractsTek());
        System.out.println("=====================3.4(未校验)用户信息Id 超时中订单与未支付超时订单检测==============================");
        checkOvertime(userCar.getUserInfoId());
        System.out.println("=====================3.5用户Id与用户信息Id是否对应==============================");
        String userInfoName = checkUserId(param.getUserId(), userCar.getUserInfoId());
        System.out.println("用户名:"+userInfoName);
        System.out.println("=====================3.6车位信息存在且上架==============================");
        StallDto stall = basicInfoUtil.getStallInfo(param.getStallInfoId());
        System.out.println("车位号:"+stall.getStallInfoArea()+String.valueOf(1000+stall.getStallInfoNum()).substring(1));
        System.out.println("车位类型Id:"+stall.getStallType()+"(0普通1充电)");
        System.out.println("物业信息Id:"+stall.getCertifiedInfoId());
        System.out.println("出租客信息Id:"+stall.getRentersInfoId()+"(null表示车位不属于出租客)");
        System.out.println("=====================3.7(未校验)返回车位时间计划==============================");
        checkPlan(param.getStartTime(),param.getEndTime(),param.getStallInfoId());
        System.out.println("====================3.8(未校验)车位订单冲突校验===============================");
        checkOrderTime(param.getStallInfoId(),param.getStartTime(),param.getEndTime());
        OrderDto orderDto = null;
        RLock lock = redissonClient.getFairLock(RedisKey.orderStallLock(param.getStallInfoId()));
        boolean isLock = lock.tryLock(10, TimeUnit.SECONDS);
        try{
            if(!isLock) throw new Exception("服务器繁忙");
            checkOrderTime(param.getStallInfoId(),param.getStartTime(),param.getEndTime());

            // 添加订单
            System.out.println("=====================4.上锁结束 方法执行===============================");
            System.out.println("=====================4.1 生成订单对象===============================");
            OrderInfo order = new OrderInfo();
            order.setUserInfoId(userCar.getUserInfoId());
            order.setCertifiedInfoId(stall.getCertifiedInfoId());
            System.out.println("=====================4.1.1插曲 查询物业信息===============================");
            CertifiedInfoDto certified = basicInfoUtil.getCertifiedInfo(stall.getCertifiedInfoId());
            System.out.println("物业账号Id:"+certified.getCertifiedAccountId());
            System.out.println("物业名称:"+certified.getCertifiedInfoName());
            System.out.println("物业电话:"+certified.getCertifiedInfoTel());
            System.out.println("物业地址:"+certified.getCertifiedInfoAddress());
            System.out.println("物业充电车位单价:"+certified.getChargeUnitPrice());
            System.out.println("物业普通车位单价:"+certified.getStallUnitPrice());
            order.setCertifiedInfoName(certified.getCertifiedInfoName());
            order.setCertifiedInfoTel(certified.getCertifiedInfoTel());
            order.setCertifiedInfoAddress(certified.getCertifiedInfoAddress());
            order.setStartTime(param.getStartTime());
            order.setEndTime(param.getEndTime());
            order.setEnduHour(enduHour);
            order.setOrderInfoState(StateData.ORDER_STATE_NO_PAID);
            order.setIsOvertime(StateData.ORDER_IS_NOT_OVERTIME);
            order.setIsComment(StateData.ORDER_IS_NOT_COMMENT);
            LocalDateTime now = LocalDateTime.now();
            order.setOrderAddTime(now);
            order.setOrderUpdateTime(now);
            Snowflake snowflake = new Snowflake(1, 1);
            String orderInfoNum = snowflake.nextIdStr();
            order.setOrderInfoNum(orderInfoNum);
            BigDecimal unitPrice = null;
            String stallType = null;
            if(Objects.equals(stall.getStallType(), StateData.STALL_TYPE_NORMAL)) {
                unitPrice = certified.getStallUnitPrice();
                stallType = "普通车位";
            }
            if(Objects.equals(stall.getStallType(), StateData.STALL_TYPE_CHARGE)) {
                unitPrice = certified.getChargeUnitPrice();
                stallType = "充电车位";
            }
            assert unitPrice != null;
            order.setOrderPrice(unitPrice.multiply(BigDecimal.valueOf(enduHour)));
            order.setStallType(stallType);
            order.setStallInfoId(param.getStallInfoId());
            order.setStallInfo(stall.getStallInfoArea()+String.valueOf(1000+stall.getStallInfoNum()).substring(1));
            order.setUserCarId(param.getUserCarId());
            order.setUserCarPlate(userCar.getUserCarPlate());
            orderInfoDao.insert(order);
            System.out.println("=====================4.1.2 订单生成完成===============================");
            System.out.println("用户信息Id:"+order.getUserInfoId());
            System.out.println("物业信息Id:"+order.getCertifiedInfoId());
            System.out.println("物业名称:"+order.getCertifiedInfoName());
            System.out.println("物业电话:"+order.getCertifiedInfoTel());
            System.out.println("物业地址:"+order.getCertifiedInfoAddress());
            System.out.println("开始时间:"+order.getStartTime());
            System.out.println("结束时间:"+order.getEndTime());
            System.out.println("整小时数:"+order.getEnduHour());
            System.out.println("订单状态:"+order.getOrderInfoState()+"(0待支付 1已支付 2可开始 3已开始 4需结束 5已结束 6已取消)");
            System.out.println("超时状态:"+order.getIsOvertime()+"(0未超时 1超时未支付 2超时已支付)");
            System.out.println("评论状态:"+order.getIsComment()+"(0未评论 1未回复 2已回复)");
            System.out.println("订单添加时间:"+order.getOrderAddTime());
            System.out.println("订单修改时间:"+order.getOrderUpdateTime());
            System.out.println("订单编号:"+order.getOrderInfoNum());
            System.out.println("订单价格:"+order.getOrderPrice());
            System.out.println("车位类型:"+order.getStallType());
            System.out.println("车位信息Id:"+order.getStallInfoId());
            System.out.println("车位号:"+order.getStallInfo());
            System.out.println("用户车辆Id:"+order.getUserCarId());
            System.out.println("车牌号:"+order.getUserCarPlate());
            System.out.println("是否自动取消:"+order.getIsAutoCancel()+"(0非自动取消 1自动取消)");
            System.out.println("订单Id:"+order.getOrderInfoId());

            // 添加订单日志
            System.out.println("=====================4.2 生成日志对象===============================");
            rabbitTemplate.convertAndSend("orderLog",orderInfoNum+",用户下单,"+StateData.ORDER_LOG_PERSON_TYPE_USER+","+userInfoName);

            // 添加延迟消息队列查询支付状态
            System.out.println("=====================4.3 延迟查询订单状态(2分钟)===============================");
            rabbitTemplate.convertAndSend("order1",orderInfoNum);

            // 返回订单Dto
            System.out.println("=======================4.4 返回订单Dto===========================");
            orderDto = BeanUtil.toBean(order,OrderDto.class);
            orderDto.setOrderInfoState("待支付");
            String startTime = DateUtil.localDateTimeToString(param.getStartTime(),"yyyy-MM-dd HH:mm");
            String endTime = DateUtil.localDateTimeToString(param.getEndTime(), "yyyy-MM-dd HH:mm");
            orderDto.setTime(startTime+" - "+endTime);
        }finally{
            lock.unlock();
        }

        return orderDto;
    }

    /**
     * 根据用户车辆Id查询关联订单
     * 参数: 用户车辆ID userCarId
     * 返回: List<UserOrderDto> 正在使用的用户订单Id 已取消和已完成的不要
     *      orderInfoId 订单Id
     *      orderInfoNum 订单编号
     * */
    @Override
    public List<UserOrderDto> selectUserOrderByUserCarId(Integer userCarId) {
        // 正在进行的订单 = 待支付&&已支付&&可开始&&已开始 or 有超时订单未支付
        return BeanUtilCommon.BeanToList(orderInfoDao.selectList(new QueryWrapper<OrderInfo>().eq("user_car_id",userCarId).and(wrapper->wrapper.in("order_info_state",Arrays.asList(StateData.ORDER_STATE_NO_PAID,StateData.ORDER_STATE_IS_PAID,StateData.ORDER_STATE_CAN_BEGIN,StateData.ORDER_STATE_BEGIN)).or().eq("is_overtime",StateData.ORDER_IS_OVERTIME_NOT_FINISH))),UserOrderDto.class);
    }

     /**
     * 出租客查询订单信息
     * 参数  出租客Id rentersId
     *      订单状态 orderInfoState 0预定订单 1正在进行 2超时订单 3取消订单 4完成订单
     *      订单更多状态
     *              0预定订单 -> 0未支付 1已支付
     *              1正在进行 -> 0未入场 1已入场
     *              2超时订单 -> 0未出场 1未支付
     *              3取消订单 -> 0手动取消 1超时取消
     *              4完成订单 -> 0未评论 1好中评 2差评
     *      车位号 stallInfo
     *      分页页数 pageNum
     *      分页大小 pageSize
     *
     *      1.分页条件查询 Page<OrderInfo>
     *      2.组装Dto返回
     *          2.1.预备订单Dto
     *          2.2.正在进行订单Dto
     *          2.3.超时订单Dto
     *          2.4.取消订单Dto
     *          2.5.完成订单Dto
     * */
    @Override
    public PageInfo findOrderRenters(FindOrderRentersParam param) throws Exception {
        // rentersId --> rentersInfoId
        // 订单further状态校验
        RentersDto renters = basicInfoUtil.getRenters(param.getRentersId());
        if(param.getOrderInfoStateFurther()!=null&&param.getOrderInfoStateFurther()>1){
            if(!Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_FINISH) && !Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_CANCEL)){
                throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_INFO_STATE_FURTHER_OUT);
            }
        }
        FindOrderParam neutralParam = BeanUtil.toBean(param, FindOrderParam.class);
        neutralParam.setRentersInfoId(renters.getRentersInfoId());
        neutralParam.setWhoAreYou("renters");

        // 查询Page<OrderInfo>-->PageInfo 组装为特定的clazz返回
        PageInfo page = findOrder(neutralParam);
        // 确定特定的clazz类 出租客4
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_ING)||Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_PRE)){
            return contomize(page, OrderDto4A.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_OVERTIME)){
            return contomize(page, OrderDto4B.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_CANCEL)){
            return contomize(page, OrderDto4C.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_FINISH)){
            return contomize(page, OrderDto4D.class);
        }
        return null;
    }

    /**
     * 用户查询订单信息
     * 参数  用户Id userId
     *      订单状态 orderInfoState 0预定订单 1正在进行 2超时订单 3取消订单 4完成订单
     *      订单更多状态
     *              0预定订单 -> 0未支付 1已支付
     *              1正在进行 -> 0未入场 1已入场
     *              2超时订单 -> 0未出场 1未支付
     *              3取消订单 -> 0手动取消 1超时取消
     *              4完成订单 -> 0未评论 1未回复 2已回复
     *      分页页数 pageNum
     *      分页大小 pageSize
     *
     *      1.分页条件查询 Page<OrderInfo>
     *      2.组装Dto返回
     *          2.1.预备订单Dto
     *          2.2.正在进行订单Dto
     *          2.3.超时订单Dto
     *          2.4.取消订单Dto
     *          2.5.完成订单Dto
     * */
    @Override
    public PageInfo findOrderUser(FindOrderUserParam param) throws Exception {
        // userId --> userInfoId
        // 订单further状态校验
        UserAccountDto user = basicInfoUtil.getUser(param.getUserId());
        if(param.getOrderInfoStateFurther()!=null&&param.getOrderInfoStateFurther()>1){
            if(!Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_FINISH) && !Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_CANCEL)){
                throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_INFO_STATE_FURTHER_OUT);
            }
        }
        FindOrderParam neutralParam = BeanUtil.toBean(param, FindOrderParam.class);
        neutralParam.setUserInfoId(user.getUserInfoId());
        neutralParam.setWhoAreYou("user");

        // 查询Page<OrderInfo>-->PageInfo 组装为特定的clazz返回
        PageInfo page = findOrder(neutralParam);
        // 确定特定的clazz类 用户2
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_ING)||Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_PRE)){
            return contomize(page, OrderDto2A.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_OVERTIME)){
            return contomize(page, OrderDto2B.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_CANCEL)){
            return contomize(page, OrderDto2C.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_FINISH)){
            return contomize(page, OrderDto2D.class);
        }
        return null;
    }

    /**
     * 平台查询订单信息
     * 参数  平台Id platformId
     *      订单状态 orderInfoState 0预定订单 1正在进行 2超时订单 3取消订单 4完成订单
     *      订单更多状态
     *              0预定订单 -> 0未支付 1已支付
     *              1正在进行 -> 0未入场 1已入场
     *              2超时订单 -> 0未出场 1未支付
     *              3取消订单 -> 0手动取消 1超时取消
     *              4完成订单 -> 0未评论 1好中评 2差评
     *      分页页数 pageNum
     *      分页大小 pageSize
     *      车位号 stallInfo
     *      物业信息Id certifiedInfoId
     *
     *      1.分页条件查询 Page<OrderInfo>
     *      2.组装Dto返回
     *          2.1.预备订单Dto
     *          2.2.正在进行订单Dto
     *          2.3.超时订单Dto
     *          2.4.取消订单Dto
     *          2.5.完成订单Dto
     * */
    @Override
    public PageInfo findOrderPlatform(FindOrderPlatformParam param) throws Exception {
        // platformId 查询是否被封禁即可
        // 订单further状态校验
        basicInfoUtil.getPlatform(param.getPlatformId());
        if(param.getOrderInfoStateFurther()!=null&&param.getOrderInfoStateFurther()>1){
            if(!Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_FINISH) && !Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_CANCEL)){
                throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_INFO_STATE_FURTHER_OUT);
            }
        }
        FindOrderParam neutralParam = BeanUtil.toBean(param, FindOrderParam.class);
        neutralParam.setWhoAreYou("platform");

        // 查询Page<OrderInfo>-->PageInfo 组装为特定的clazz返回
        PageInfo page = findOrder(neutralParam);
        // 确定特定的clazz类 平台1
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_ING)||Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_PRE)){
            return contomize(page, OrderDto1A.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_OVERTIME)){
            return contomize(page, OrderDto1B.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_CANCEL)){
            return contomize(page, OrderDto1C.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_FINISH)){
            return contomize(page, OrderDto1D.class);
        }
        return null;
    }

    /**
     * 物业查询订单信息
     * 参数  物业Id certifiedId
     *      订单状态 orderInfoState 0预定订单 1正在进行 2超时订单 3取消订单 4完成订单
     *      订单更多状态
     *              0预定订单 -> 0未支付 1已支付
     *              1正在进行 -> 0未入场 1已入场
     *              2超时订单 -> 0未出场 1未支付
     *              3取消订单 -> 0手动取消 1超时取消
     *              4完成订单 -> 0未评论 1好中评 2差评未回复 3差评已回复
     *      分页页数 pageNum
     *      分页大小 pageSize
     *      车位号 stallInfo
     *
     *      1.分页条件查询 Page<OrderInfo>
     *      2.组装Dto返回
     *          2.1.预备订单Dto
     *          2.2.正在进行订单Dto
     *          2.3.超时订单Dto
     *          2.4.取消订单Dto
     *          2.5.完成订单Dto
     * */
    @Override
    public PageInfo findOrderCertified(FindOrderCertifiedParam param) throws Exception {
        // certifiedId --> certifiedInfoId
        // 订单further状态校验
        CertifiedAccountDto certified = basicInfoUtil.getCertifiedAccount(param.getCertifiedId());
        if(param.getOrderInfoStateFurther()!=null&&param.getOrderInfoStateFurther()>1){
            if(!Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_FINISH) && !Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_CANCEL)){
                throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_INFO_STATE_FURTHER_OUT);
            }
            if(Objects.equals(param.getOrderInfoState(),StateData.ORDER_STATE_SEARCH_CANCEL)&&Objects.equals(param.getOrderInfoStateFurther(),StateData.ORDER_STATE_FURTHER_FINISH_BAD_REPLIED)){
                throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_INFO_STATE_FURTHER_OUT);
            }
        }
        FindOrderParam neutralParam = BeanUtil.toBean(param, FindOrderParam.class);
        neutralParam.setCertifiedInfoId(certified.getCertifiedInfoId());
        neutralParam.setWhoAreYou("certified");

        // 查询Page<OrderInfo>-->PageInfo 组装为特定的clazz返回
        PageInfo page = findOrder(neutralParam);
        // 确定特定的clazz类 物业3
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_ING)||Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_PRE)){
            return contomize(page, OrderDto3A.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_OVERTIME)){
            return contomize(page, OrderDto3B.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_CANCEL)){
            return contomize(page, OrderDto3C.class);
        }
        if(Objects.equals(param.getOrderInfoState(), StateData.ORDER_STATE_SEARCH_FINISH)){
            return contomize(page, OrderDto3D.class);
        }
        return null;
    }

    /**
     * 用户支付接口
     * 参数 orderInfoNum 订单编号 超时订单长度20 普通订单长度19
     * */
    @Override
    public String pay(PayParam param) throws Exception {
        System.out.println("===================1 初始参数 ==========================");
        System.out.println("用户Id:"+param.getUserId()+"存在且状态正常");

        OrderInfo order = null;
        OrderOvertime overtime = null;
        long length = param.getOrderInfoNum().length();
        Integer userInfoId = basicInfoUtil.getUser(param.getUserId()).getUserInfoId();
        if(length==StateData.ORDER_NUM_LENGTH_SNOWFLAKE){
            System.out.println("订单编号:"+param.getOrderInfoNum()+"19位普通订单");
            order = orderInfoDao.selectOne(new QueryWrapper<OrderInfo>().eq("order_info_num", param.getOrderInfoNum()));
            System.out.println("===========================2 校验============================");
            if(order==null) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_NOT_EXISTS);
            if(!Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_NO_PAID)) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_WRONG_ORDER_STATE);
            System.out.println("==============================2.1 订单编号存在且状态未支付");
            if(!Objects.equals(order.getUserInfoId(), userInfoId)) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_NOT_BELONG_TO_THIS_USER);
            System.out.println("==============================2.2 订单用户Id与用户Id对应");
        }
        if(length==StateData.ORDER_NUM_OVERTIME_LENGTH_SNOWFLAKE){
            System.out.println("订单编号:"+param.getOrderInfoNum()+"20位超时订单");
            overtime = orderOvertimeDao.selectOne(new QueryWrapper<OrderOvertime>().eq("order_info_num",StateData.fromOvertimeNumToOrder(param.getOrderInfoNum())));
            if(overtime==null) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_NO_OVERTIME_INFO);
            if(!Objects.equals(overtime.getPayState(), StateData.ORDER_OVERTIME_NOT_PAY)) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_OVERTIME_ALREADY_PAID);
            if(!Objects.equals(overtime.getUserInfoId(), userInfoId)) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_NOT_BELONG_TO_THIS_USER);
        }

        String orderInfoNum = param.getOrderInfoNum().length()==StateData.ORDER_NUM_LENGTH_SNOWFLAKE?param.getOrderInfoNum():StateData.fromOvertimeNumToOrder(param.getOrderInfoNum());
        BigDecimal orderPrice = null;
        if(order!=null) orderPrice = order.getOrderPrice();
        if(overtime!=null) orderPrice = overtime.getPayPrice();

        AlipayParam alipayParam = new AlipayParam();
        alipayParam.setOrderId(param.getOrderInfoNum());
        assert orderPrice != null;
        alipayParam.setMoney(orderPrice.doubleValue());
        alipayParam.setSubject("共享车位");
        alipayParam.setBody("车位租借");
        alipayParam.setReturnUrl("www.baidu.com");
        // 支付宝回调接口
        alipayParam.setNotifyUrl(StateData.PAY_NOTIFY_URL_PRE+"/order/orderInfo/orderNotify");

        System.out.println("========================3 生成支付宝支付参数=============");
        System.out.println("订单编号:"+param.getOrderInfoNum());
        System.out.println("支付金额:"+alipayParam.getMoney());
        System.out.println("支付主题:"+alipayParam.getSubject());
        System.out.println("支付主体:"+alipayParam.getBody());
        System.out.println("返回链接:"+alipayParam.getReturnUrl());
        System.out.println("回调接口:"+alipayParam.getNotifyUrl());
        // 支付宝回调
        if(length==StateData.ORDER_NUM_OVERTIME_LENGTH_SNOWFLAKE){
            rabbitTemplate.convertAndSend("order1",param.getOrderInfoNum());
        }

        if(length==StateData.ORDER_NUM_LENGTH_SNOWFLAKE){
            System.out.println("========================3 返回支付HTML=============");
        }
        return alipayUtil.pay(alipayParam);
    }

    /**
     * 支付宝回调接口
     * 参数 请求参数 HttpServletRequest
     * 返回 成功信息 "SUCCESS"
     * */
    @Override
    @Transactional
    public void updateOrderState(Map<String, String> params) throws Exception {
        boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfiguration.getAlipayPublicKey(),"utf-8", "RSA2");
        if(signVerified){
            String orderInfoNum = params.get("out_trade_no");
            String tradeStatus = params.get("trade_status");
            if(tradeStatus.equals("TRADE_SUCCESS")) {
                LocalDateTime now = LocalDateTime.now();
                if(orderInfoNum.length()==StateData.ORDER_NUM_LENGTH_SNOWFLAKE){
                    OrderInfo order = orderInfoDao.selectOne(new QueryWrapper<OrderInfo>().eq("order_info_num",orderInfoNum));
                    if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_NO_PAID)){
                        System.out.println("===============检测结果:普通订单支付=======================");
                        Integer type = StateData.ORDER_STATE_NOPAY_TO_PAID_ALIPAY;
                        System.out.println("当前时间:"+now);
                        System.out.println("支付时间:"+now);
                        if(now.isBefore(order.getStartTime())) {
                            System.out.println("===============现在订单还未开始 进入已支付状态=======================");
                            commonOrderStateChange.stateChangeNopayToPaid(orderInfoNum,type,now);
                        }
                        else {
                            System.out.println("===============现在订单已经开始 进入可开始状态=======================");
                            commonOrderStateChange.stateChangeNopayToShbegin(orderInfoNum,type,now);
                        }
                    }
                }
                if(orderInfoNum.length()==StateData.ORDER_NUM_OVERTIME_LENGTH_SNOWFLAKE){
                    // 超时订单支付
                    orderInfoNum = StateData.fromOvertimeNumToOrder(orderInfoNum);

                    OrderOvertime overtime = orderOvertimeDao.selectOne(new QueryWrapper<OrderOvertime>().eq("order_info_num",orderInfoNum));
                    if(Objects.equals(overtime.getPayState(), StateData.ORDER_OVERTIME_NOT_PAY)){
                        System.out.println("===============检测结果:超时订单支付=======================");
                        orderInfoDao.update(null,new UpdateWrapper<OrderInfo>().eq("order_info_num",orderInfoNum).set("order_info_state",StateData.ORDER_STATE_END).set("is_overtime",StateData.ORDER_IS_OVERTIME_FINISH).set("order_update_time",now));

                        overtime.setPayState(StateData.ORDER_OVERTIME_PAID);
                        overtime.setPayTime(now);
                        overtime.setUpdateTime(now);
                        orderOvertimeDao.updateById(overtime);

                        rabbitTemplate.convertAndSend("orderLog",orderInfoNum+",用户支付超时订单 消息队列查询支付状态延迟确认,"+StateData.ORDER_LOG_PERSON_TYPE_SYSTEM+",系统自动");

                        rabbitTemplate.convertAndSend("moneyOvertime",orderInfoNum);

                        int badCommentNum = Integer.parseInt(redisUtil.get(RedisKey.certifiedOrderOvertime(overtime.getCertifiedInfoId())));
                        redisUtil.set(RedisKey.certifiedOrderOvertime(overtime.getCertifiedInfoId()), String.valueOf(badCommentNum-1));
                    }
                }
            }
        }
    }

    /**
     * 用户退单
     * 参数 用户Id userId
     *     订单编号 orderInfoNum
     * 返回 额外信息 如是否半额退单等
     * */
    @Override
    public String refund(RefundParam param) throws Exception {
        String extraMessage = "";

        System.out.println("======================开始退款流程=======================");

        // 校验用户与订单
        OrderInfo order = orderInfoDao.selectOne(new QueryWrapper<OrderInfo>().eq("order_info_num",param.getOrderInfoNum()));
        UserAccountDto user = basicInfoUtil.getUser(param.getUserId());
        if(order==null) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_NOT_EXISTS);
        if(!Objects.equals(order.getUserInfoId(), user.getUserInfoId())) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_NOT_BELONG_TO_THIS_USER);
        if(!Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_IS_PAID)&&!Objects.equals(order.getOrderInfoState(),StateData.ORDER_STATE_NO_PAID)) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_WRONG_ORDER_STATE);

        LocalDateTime now = LocalDateTime.now();

        System.out.println("订单当前状态:"+order.getOrderInfoState()+"(0待支付 1已支付 2可开始 3已开始 4需结束 5已结束 6已取消)");
        if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_NO_PAID)){
            // 未付款订单退款
            // 1.是否真的未付款 2.时间上是否已经错过退款时间
            String payState = alipayUtil.selectOrderPayState(order.getOrderInfoNum());
            JSONObject jsonObject = JSONUtil.parseObj(JSONUtil.parseObj(payState).getStr("alipay_trade_query_response"));
            String trade_status = jsonObject.getStr("trade_status");
            if ("TRADE_SUCCESS".equals(trade_status)) {
                // 其实付款了
                String payTimeStr = jsonObject.getStr("send_pay_date");
                DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime payTime = LocalDateTime.parse(payTimeStr,pattern);
                Integer type = StateData.ORDER_STATE_NOPAY_TO_PAID_USER;
                if(now.isBefore(order.getStartTime())) {
                    order.setOrderInfoState(StateData.ORDER_STATE_IS_PAID);
                    order.setOrderPayTime(payTime);
                    order.setOrderUpdateTime(now);
                    orderInfoDao.updateById(order);

                    // 生成订单日志
                    String orderLogsDescribe = "用户申请退单 查询支付状态时发现已支付 但时间上仍可申请退单";
                    Integer logType = StateData.ORDER_LOG_PERSON_TYPE_USER;
                    UserInfoDto userInfo = basicInfoUtil.getUserInfo(order.getUserInfoId());
                    String logger = userInfo.getUserInfoName();
                    System.out.println("================2 生成订单日志================================");
                    rabbitTemplate.convertAndSend("orderLog",order.getOrderInfoNum()+","+orderLogsDescribe+","+logType+","+logger);

                    // 生成订单流水表
                    System.out.println("================3 添加订单流水================================");
                    rabbitTemplate.convertAndSend("moneyByAdd",order.getOrderInfoNum());
                }else {
                    //commonOrderStateChange.stateChangeNopayToShbegin(order.getOrderInfoNum(),type,payTime);

                    order.setOrderInfoState(StateData.ORDER_STATE_CAN_BEGIN);
                    order.setOrderPayTime(payTime);
                    order.setOrderUpdateTime(now);
                    orderInfoDao.updateById(order);

                    // 生成订单日志
                    String orderLogsDescribe = "用户申请退单 查询支付状态时发现已支付 但已经开启服务不能退单";
                    Integer logType = StateData.ORDER_LOG_PERSON_TYPE_USER;
                    UserInfoDto userInfo = basicInfoUtil.getUserInfo(order.getUserInfoId());
                    String logger = userInfo.getUserInfoName();
                    System.out.println("================2 生成订单日志================================");
                    rabbitTemplate.convertAndSend("orderLog",order.getOrderInfoNum()+","+orderLogsDescribe+","+logType+","+logger);

                    // 生成订单流水表
                    System.out.println("================3 添加订单流水================================");
                    rabbitTemplate.convertAndSend("moneyByAdd",order.getOrderInfoNum());

                    throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_CAN_BEGIN_NO_REFUND);
                }
            }else {
                // 真的未付款
                //commonOrderStateChange.stateChangeNopayToCancel(order.getOrderInfoNum(),StateData.ORDER_STATE_NOPAY_TO_PAID_ALIPAY);
                System.out.println("===========真的未付款=============");
                order.setOrderInfoState(StateData.ORDER_STATE_CANCELED);
                order.setIsAutoCancel(StateData.ORDER_STATE_CANCEL_BY_USER);
                order.setOrderUpdateTime(now);
                orderInfoDao.updateById(order);

                String orderLogsDescribe = "用户未支付状态取消订单 经确认确实未支付";
                Integer logType = StateData.ORDER_LOG_PERSON_TYPE_USER;
                String logger = basicInfoUtil.getUserInfo(order.getUserInfoId()).getUserInfoName();
                System.out.println("===============生成订单日志=======================");
                rabbitTemplate.convertAndSend("orderLog",order.getOrderInfoNum()+","+orderLogsDescribe+","+logType+","+logger);
            }
        }

        System.out.println("订单当前状态:"+order.getOrderInfoState()+"(0待支付 1已支付 2可开始 3已开始 4需结束 5已结束 6已取消)");

        if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_IS_PAID)){
            // 已付款订单退款
            if(now.isBefore(order.getStartTime().minusMinutes(30))){
                // 全额退款 isHalf=false
                System.out.println("全额退款");
                extraMessage = "(全额退款)";

                order.setOrderInfoState(StateData.ORDER_STATE_CANCELED);
                order.setIsAutoCancel(StateData.ORDER_STATE_CANCEL_BY_USER);
                order.setOrderUpdateTime(now);
                orderInfoDao.updateById(order);

                String orderLogsDescribe = "用户支付状态退款"+"(全额)";
                Integer logType = StateData.ORDER_LOG_PERSON_TYPE_USER;
                UserInfoDto userInfo = basicInfoUtil.getUserInfo(order.getUserInfoId());
                String logger = userInfo.getUserInfoName();
                rabbitTemplate.convertAndSend("orderLog",order.getOrderInfoNum()+","+orderLogsDescribe+","+logType+","+logger);

                rabbitTemplate.convertAndSend("moneyByDelete",order.getOrderInfoNum()+","+false);

            }else{
                // 半额退款 isHalf=true

                System.out.println("半额退款");
                extraMessage = "(原订单服务将在半小时内开启 故半额退款)";

                order.setOrderInfoState(StateData.ORDER_STATE_CANCELED);
                order.setIsAutoCancel(StateData.ORDER_STATE_CANCEL_BY_USER);
                order.setOrderUpdateTime(now);
                orderInfoDao.updateById(order);

                String orderLogsDescribe = "用户支付状态退款"+("(半额)");
                Integer logType = StateData.ORDER_LOG_PERSON_TYPE_USER;
                UserInfoDto userInfo = basicInfoUtil.getUserInfo(order.getUserInfoId());
                String logger = userInfo.getUserInfoName();
                rabbitTemplate.convertAndSend("orderLog",order.getOrderInfoNum()+","+orderLogsDescribe+","+logType+","+logger);

                rabbitTemplate.convertAndSend("moneyByDelete",order.getOrderInfoNum()+","+true);

            }
        }

        return extraMessage;
    }

    /**
     *userSelectTimeQuantum：筛选出符合时间范围内的所有订单的车位信息id
     * 参数 startTime 开始时间
     *      endTime 结束时间
     * @return  Set<Integer>   车位的ids集合
     *                          1.有时间交集的订单对应的车位Id
     *                          2.超时的订单对应的车位Id
     * @throws Exception
     */
    @Override
    public Set<Integer> userSelectTimeQuantum(LocalDateTime startTime, LocalDateTime endTime) {
        // 有时间交集的订单对应的车位Id
        // 时间区间交集算法 AStart<BEnd&&BStart<AEnd
        List<OrderInfo> orders1 = orderInfoDao.selectList(new QueryWrapper<OrderInfo>().lt("start_time",endTime).gt("end_time",startTime));
        // 超时订单对应的车位Id
        List<OrderInfo> orders2 = orderInfoDao.selectList(new QueryWrapper<OrderInfo>().eq("order_info_state", StateData.ORDER_STATE_SHOULD_END));

        Set<Integer> set = new HashSet<>();
        for (OrderInfo order : orders1) {
            set.add(order.getStallInfoId());
        }
        for (OrderInfo order : orders2) {
            set.add(order.getStallInfoId());
        }
        return set;
    }

    /**
     * 工具函数 查询订单
     * 参数 pageNum 页数
     *     pageSize 每页大小
     *     orderInfoState 订单状态
     *     orderInfoStateFurther 更多订单状态
     *     userInfoId 用户信息Id
     *     certifiedInfoId 物业信息Id
     *     stallInfoId 车位信息Id
     *     rentersInfoId 出租客信息Id
     *     whoAreYou 身份 renters user platform certified
     * */
    public PageInfo findOrder(FindOrderParam param) throws Exception {
        Page<OrderInfo> page = new Page<>(param.getPageNum(),param.getPageSize());
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();


        // 拼凑查询条件
        boolean isOrderFurtherState = param.getOrderInfoStateFurther()!=null;
        boolean isStallInfo = param.getStallInfo()!=null&&!param.getStallInfo().equals("");
        boolean isUserInfoId = param.getUserInfoId()!=null;
        boolean isCertifiedInfoId = param.getCertifiedInfoId()!=null;
        boolean isRentersInfoId = param.getRentersInfoId()!=null;

        // 1. orderInfoState orderFurtherState
        Integer orderState = param.getOrderInfoState();
        Integer orderStateFurther = param.getOrderInfoStateFurther();
        String whoAreYou = param.getWhoAreYou();
        if(Objects.equals(orderState, StateData.ORDER_STATE_SEARCH_PRE)){
            if(isOrderFurtherState){
                if(Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_PRE_NO_PAY)){
                    wrapper.eq("order_info_state",StateData.ORDER_STATE_NO_PAID);
                }
                if(Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_PRE_PAID)){
                    wrapper.eq("order_info_state",StateData.ORDER_STATE_IS_PAID);
                }
            }

            if(!isOrderFurtherState){
                wrapper.in("order_info_state",Arrays.asList(StateData.ORDER_STATE_IS_PAID,StateData.ORDER_STATE_NO_PAID));
            }
        }
        if(Objects.equals(orderState,StateData.ORDER_STATE_SEARCH_ING)){
            if(isOrderFurtherState){
                if(Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_ING_COME)){
                    wrapper.eq("order_info_state",StateData.ORDER_STATE_BEGIN);
                }
                if(Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_ING_NO_COME)){
                    wrapper.eq("order_info_state",StateData.ORDER_STATE_CAN_BEGIN);
                }
            }

            if(!isOrderFurtherState){
                wrapper.in("order_info_state",Arrays.asList(StateData.ORDER_STATE_BEGIN,StateData.ORDER_STATE_CAN_BEGIN));
            }
        }
        if(Objects.equals(orderState, StateData.ORDER_STATE_SEARCH_OVERTIME)){
            if(isOrderFurtherState){
                if(Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_OVERTIME_NOT_OUT)){
                    wrapper.eq("order_info_state",StateData.ORDER_STATE_SHOULD_END);
                }

                if(Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_OVERTIME_NOT_PAY)){
                    wrapper.eq("order_info_state",StateData.ORDER_STATE_END).eq("is_overtime",StateData.ORDER_IS_OVERTIME_NOT_FINISH);
                }
            }

            if(!isOrderFurtherState){
                wrapper.and(rapper->rapper
                            .eq("order_info_state",StateData.ORDER_STATE_SHOULD_END)
                            .or(apper -> apper.eq("order_info_state",StateData.ORDER_STATE_END)
                                              .eq("is_overtime",StateData.ORDER_IS_OVERTIME_NOT_FINISH)));
            }
        }
        if(Objects.equals(orderState, StateData.ORDER_STATE_SEARCH_CANCEL)){
            if(isOrderFurtherState){
                if(Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_CANCEL_NOPAY)){
                    wrapper.eq("order_info_state",StateData.ORDER_STATE_CANCELED).eq("is_auto_cancel",StateData.ORDER_STATE_CANCEL_BY_SYSTEM);
                }
                if(Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_CANCEL_USER)){
                    wrapper.eq("order_info_state",StateData.ORDER_STATE_CANCELED).eq("is_auto_cancel",StateData.ORDER_STATE_CANCEL_BY_USER);
                }
                if(Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_CANCEL_AUTO)){
                    wrapper.eq("order_info_state",StateData.ORDER_STATE_CANCELED).eq("is_auto_cancel",StateData.ORDER_STATE_IS_AUTO_CANCEL);
                }
            }

            if(!isOrderFurtherState){
                wrapper.eq("order_info_state",StateData.ORDER_STATE_CANCELED);
            }
        }
        if(Objects.equals(orderState, StateData.ORDER_STATE_SEARCH_FINISH)){
            if(isOrderFurtherState){
                if(Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_FINISH_NO_COMMENT)){
                    wrapper.eq("order_info_state",StateData.ORDER_STATE_END).ne("is_overtime",StateData.ORDER_IS_OVERTIME_NOT_FINISH).eq("is_comment",StateData.ORDER_IS_NOT_COMMENT);
                }
                if(Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_FINISH_BAD_REPLIED)){
                    // 评论 -> 订单已结束 && 订单若超时则已支付
                    wrapper.eq("is_comment",StateData.ORDER_IS_REPLY).eq("comment_score","Bad");
                }
                if(whoAreYou.equals("user")&&Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_FINISH_NO_REPLY)){
                    wrapper.eq("is_comment",StateData.ORDER_IS_COMMENT_NO_REPLY);
                }
                if(!whoAreYou.equals("user")&&Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_FINISH_GOOD_OR_OK)){
                    wrapper.eq("comment_score",Arrays.asList("Good","OK"));
                }
                if((whoAreYou.equals("renters")||whoAreYou.equals("platform"))&&Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_FINISH_BAD)){
                    wrapper.eq("comment_score","Bad");
                }
                if(whoAreYou.equals("user")&&Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_FINISH_REPLIED)){
                    wrapper.eq("is_comment", StateData.ORDER_IS_REPLY);
                }
                if(whoAreYou.equals("certified")&&Objects.equals(orderStateFurther,StateData.ORDER_STATE_FURTHER_FINISH_BAD_NO_REPLY)){
                    wrapper.eq("is_comment",StateData.ORDER_IS_COMMENT_NO_REPLY).eq("comment_score","Bad");
                }
            }

            if(!isOrderFurtherState){
                wrapper.eq("order_info_state",StateData.ORDER_STATE_END).ne("is_overtime",StateData.ORDER_IS_OVERTIME_NOT_FINISH);
            }
        }

        // 2.stallInfo userInfoId certifiedInfoId
        if(isStallInfo) wrapper.eq("stall_info",param.getStallInfo());
        if(isUserInfoId) wrapper.eq("user_info_id",param.getUserInfoId());
        if(isCertifiedInfoId) wrapper.eq("certified_info_id",param.getCertifiedInfoId());

        // 3.rentersInfoId
        if(isRentersInfoId){
            List<StallDto> stalls = basicInfoUtil.getStallInfoByRentersId(param.getRentersInfoId());
            List<Integer> stallInfoIds = stalls.stream().map(StallDto::getStallInfoId).collect(Collectors.toList());
            stallInfoIds.add(0); // 防止空集
            wrapper.in("stall_info_id",stallInfoIds);
        }
        wrapper.orderByDesc("order_update_time");

        orderInfoDao.selectPage(page,wrapper);

        List<OrderInfoDto> dtos = new ArrayList<>();
        for (OrderInfo order : page.getRecords()) {
            OrderInfoDto dto = BeanUtil.toBean(order,OrderInfoDto.class);
            // OrderInfo --> OrderInfoDto
            dto.setOrderCancelTime(order.getOrderUpdateTime());
            UserInfoDto user = basicInfoUtil.getUserInfo(dto.getUserInfoId());
            dto.setUserInfoName(user.getUserInfoName());
            dto.setUserInfoTel(user.getUserInfoTel());
            // 只有需要车辆信息才返回车辆信息
            if(Objects.equals(orderState, StateData.ORDER_STATE_SEARCH_OVERTIME)){
                UserCarDto userCar = basicInfoUtil.getUserCar(dto.getUserCarId());
                dto.setCarContacksTek(userCar.getCarContractsTek());
                dto.setCarContacks(userCar.getCarContacts());
                if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_SHOULD_END)){
                    dto.setOrderState("未出场");
                }
                if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_END) && Objects.equals(order.getIsOvertime(), StateData.ORDER_IS_OVERTIME_NOT_FINISH)){
                    dto.setOrderState("已出场");
                }
            }
            if(Objects.equals(orderState, StateData.ORDER_STATE_SEARCH_PRE)){
                if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_NO_PAID)){
                    dto.setOrderState("未支付");
                }
                if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_IS_PAID)){
                    dto.setOrderState("已支付");
                }
            }
            if(Objects.equals(orderState, StateData.ORDER_STATE_SEARCH_ING)){
                if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_CAN_BEGIN)){
                    dto.setOrderState("未入场");
                }
                if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_BEGIN)){
                    dto.setOrderState("已入场");
                }
            }
            if(Objects.equals(orderState, StateData.ORDER_STATE_SEARCH_CANCEL)){
                if(Objects.equals(order.getIsAutoCancel(), StateData.ORDER_STATE_CANCEL_BY_SYSTEM)){
                    dto.setOrderState("未支付系统取消");
                }
                if(Objects.equals(order.getIsAutoCancel(), StateData.ORDER_STATE_CANCEL_BY_USER)){
                    dto.setOrderState("用户取消");
                }
                if(Objects.equals(order.getIsAutoCancel(), StateData.ORDER_STATE_IS_AUTO_CANCEL)){
                    dto.setOrderState("车位占用系统取消");
                }
            }
            if(Objects.equals(orderState, StateData.ORDER_STATE_SEARCH_FINISH)){
                if(Objects.equals(order.getIsComment(),StateData.ORDER_IS_NOT_COMMENT)){
                    dto.setOrderState("未评论");
                }
                if(Objects.equals(order.getIsComment(),StateData.ORDER_IS_COMMENT_NO_REPLY)){
                    dto.setOrderState("已评论未回复");
                }
                if(Objects.equals(order.getIsComment(),StateData.ORDER_IS_REPLY)){
                    dto.setOrderState("已回复");
                }
            }
            dtos.add(dto);
        }
        PageInfo pageInfo = BeanUtil.toBean(page, PageInfo.class);
        pageInfo.setPages(page.getPages());
        pageInfo.setTotal(page.getTotal());
        pageInfo.setRecords(dtos);
        return pageInfo;
    }

    /**
     * 工具函数 判断开始结束时间是否合规
     *
     * 参数 startTime 服务开始时间
     *     endTime   服务结束时间
     * 返回 enduHour 持续小时数
     *
     * 方法内容  1，开始时间<结束时间
     *         2. 开始时间/结束时间为最近两天
     *         3. 开始时间/结束时间分钟数为00/15/30/45
     *         4. 结束时间 - 开始时间为整小时数 = enduHour
     * */
    public Integer checkStartEnd(LocalDateTime startTime,LocalDateTime endTime){
        if(!startTime.isBefore(endTime)) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_TIME_START_NOT_BEFORE_END);

        boolean flagStart = startTime.toLocalDate().isEqual(LocalDate.now()) || startTime.toLocalDate().isEqual(LocalDate.now().plusDays(1));
        boolean flagEnd = endTime.toLocalDate().isEqual(LocalDate.now()) || endTime.toLocalDate().isEqual(LocalDate.now().plusDays(1));
        if(!flagStart||!flagEnd) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_TIME_THESE_TWO_DAYS);

        //if(startTime.getMinute()%15!=0||endTime.getMinute()%15!=0) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_TIME_MINUTES_AND_SECONDS);

        if(startTime.getMinute()!=endTime.getMinute()) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_TIME_TOTAL_HOURS);

        return Math.toIntExact(Duration.between(startTime, endTime).toHours());
    }

    /**
     * 工具函数 判断该车位的出租计划是否包含订单时间段
     *
     * 参数 startTime   服务开始时间
     *     endTime     服务结束时间
     *     stallInfoId 车位信息Id
     * */
    public void checkPlan(LocalDateTime startTime,LocalDateTime endTime,Integer stallInfoId) throws Exception {
        StallRentDto plan = basicInfoUtil.getStallRent(stallInfoId);
//        System.out.println("计划:"+ plan);
//
//        System.out.println("是否存在计划:"+plan.getIsPlan()+"(0有计划 1无计划)");
//        System.out.println("计划开始日期:"+plan.getStartDate()+"(开始结束日期同时null 表示每天)");
//        System.out.println("计划结束日期:"+plan.getEndDate());
//        System.out.println("==========================每日出租计划=============");
//        if(!plan.getPlanTimes().isEmpty()){
//            for (TimeDto planTime : plan.getPlanTimes()) {
//                System.out.println("开始时间:"+planTime.getStartTime()+" 结束时间:"+planTime.getEndTime());
//            }
//        }else System.out.println("没有时间计划");









        if(Objects.equals(plan.getIsPlan(), StateData.STALL_IS_NOT_PLAN)) return;

        LocalDate startDate = plan.getStartDate();
        LocalDate endDate = plan.getEndDate();
        Set<TimeDto> times = plan.getPlanTimes();
        LocalDate startOrderDate = startTime.toLocalDate();
        LocalDate endOrderDate = endTime.toLocalDate();

        if(startOrderDate.isEqual(endOrderDate)){
            LocalDate orderDate = startOrderDate;
            if(dateIsInDateIntervals(orderDate,startDate,endDate)){
                checkStartEndTime(times,startTime.getHour(),endTime.getHour()+(endTime.getMinute()==0?0:1));
            }
        }

        if(startOrderDate.isBefore(endOrderDate)){
            if(dateIsInDateIntervals(startOrderDate,startDate,endDate)){
                checkStartEndTime(times,startTime.getHour(),24);
            }
            if(dateIsInDateIntervals(endOrderDate,startDate,endDate)){
                checkStartEndTime(times,0,endTime.getHour()+(endTime.getMinute()==0?0:1));
            }
        }
    }

    /**
     * 工具函数 判断给定开始结束时间是否包含于某个每日出租时间
     *
     * 参数 startTime   服务开始小时数
     *     endTime     服务结束小时数
     *     times       每日出租时间组
     * */
    public void checkStartEndTime(Set<TimeDto> times, Integer startTime, Integer endTime){
        System.out.println("==========================开始比较==========================");
        System.out.println("选择开始:"+startTime);
        System.out.println("选择结束:"+endTime);
        for (TimeDto time : times) {
            System.out.println("计划开始:"+time.getStartTime());
            System.out.println("计划结束:"+time.getEndTime());
            if (time.getStartTime()<=startTime&&endTime<=time.getEndTime()) {
                System.out.println("比较成功");
                return;
            }
            System.out.println("比较失败");
        }
        throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_TIME_STALL_TIME_NOT_MATCH);
    }

    /**
     * 工具函数 判断给定日期是否位于日期段中
     *
     * 参数 date      日期
     *     startDate 日期段开始
     *     endDate   日期段结束
     * 返回 boolean值 true 表示 日期位于日期段之间
     * */
    public boolean dateIsInDateIntervals(LocalDate date, LocalDate startDate, LocalDate endDate){
        if(startDate==null||endDate==null) return true;
        return !date.isBefore(startDate)&&!date.isAfter(endDate);
    }

    /**
     * 工具函数 判断用户Id与用户信息Id是否对应
     *
     * 参数 userId       用户Id
     *     userInfoId   用户信息Id
     * 返回 userInfoName 用户名
     * */
    public String checkUserId(Integer userId, Integer userInfoId) throws Exception {
        UserInfoDto userInfo = basicInfoUtil.getUserInfo(userInfoId);
        if(!Objects.equals(userId, userInfo.getUserAccountId())) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_USER_CAR_AND_ID_NOT_MATCH);
        return userInfo.getUserInfoName();
    }

    /**
     * 工具函数 根据车位的订单Id信息判断开始结束时间是否合适
     *
     * 参数 stallInfoId 车位信息Id
     *     startTime   服务开始时间
     *     endTime     服务结束时间
     *
     * 方法流程 1.该车位存在[应结束]订单 抛异常
     *         2.该车位存在[可开始]or[应开始]订单 且 startTime>订单结束时间 抛异常
     *         3.该车位存在[待支付]or[已支付]订单 且 [startTime,endTime] [订单开始时间,订单结束时间] 有区间交集 抛异常
     * */
    public void checkOrderTime(Integer stallInfoId,LocalDateTime startTime,LocalDateTime endTime){
        List<OrderInfo> orders = orderInfoDao.selectList(new QueryWrapper<OrderInfo>().eq("stall_info_id",stallInfoId).in("order_info_state", Arrays.asList(StateData.ORDER_STATE_NO_PAID,StateData.ORDER_STATE_IS_PAID,StateData.ORDER_STATE_CAN_BEGIN,StateData.ORDER_STATE_BEGIN,StateData.ORDER_STATE_SHOULD_END)));
        for (OrderInfo order : orders) {
            LocalDateTime orderStartTime = order.getStartTime();
            LocalDateTime orderEndTime = order.getEndTime();

            if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_SHOULD_END)){
                throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_STALL_ORDER_OVERTIME_EXISTS);
            }

            if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_CAN_BEGIN)
                    ||Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_BEGIN)){
                if(startTime.isBefore(orderEndTime)){
                    throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_STALL_ORDER_TIME_CONFLICTS);
                }
            }

            if(Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_NO_PAID)
                    ||Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_IS_PAID)){
                // 时间区间交集算法 AStart<BEnd&&BStart<AEnd
                if(startTime.isBefore(orderEndTime)&&orderStartTime.isBefore(endTime)){
                    throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_STALL_ORDER_TIME_CONFLICTS);
                }
            }
        }
    }

    /**
     * 工具函数 判断用户是否存在超时订单
     *
     * 参数 userInfoId 用户信息Id
     *
     * 方法流程 1.存在[需结束]订单 抛异常
     *         2.存在未支付的超时订单 抛异常
     * */
    public void checkOvertime(Integer userInfoId){
        long count = orderInfoDao.selectCount(new QueryWrapper<OrderInfo>().eq("user_info_id",userInfoId).eq("order_info_state",StateData.ORDER_STATE_SHOULD_END));
        if(count>0) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_OVERTIME_ING);
        count = orderOvertimeDao.selectCount(new QueryWrapper<OrderOvertime>().eq("user_info_id",userInfoId).eq("pay_state",StateData.ORDER_OVERTIME_NOT_PAY));
        if(count==1) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_OVERTIME_NOT_PAID);
    }

    /**
     * 将OrderInfoDto根据不同的身份和订单状态 转换为合适的clazz
     * 参数 page 分页查询对象
     *     clazz 合适的类对象
     *  返回 经过clazz改造后的分页查询对象
     * */
    public <T> PageInfo contomize(PageInfo page, Class<T> clazz){
        List<T> orderTs = new ArrayList<>();
        for (Object record : page.getRecords()) {
            OrderInfoDto order = (OrderInfoDto) record;
            T orderT = BeanUtil.toBean(order,clazz);
            orderTs.add(orderT);
        }
        page.setRecords(orderTs);
        return page;
    }
}
